var ip_data_file = "./qqwry.dat";

var fs = require('fs');

var iconv = require('iconv-lite');

var china_city_mapping = require('./city.js');

var bind_port = 8000;

var ip_buf = fs.readFileSync(ip_data_file);

//console.log(ip_buf.length);


begin = ip_buf.slice(0,4);
end   = ip_buf.slice(4,8);
ipbegin = begin.readUInt32LE(0);
ipend   = end.readUInt32LE(0)

if(ipbegin<0) ipbegin += Math.pow(2,32);
if(ipend<0)   ipend   += Math.pow(2,32);

var ipallnum = (ipend-ipbegin)/7 +1;


function search(_ip){
	if(typeof _ip == 'undefined') return {"contry":"","info":""};
	_ip = _ip.replace(/\n\r/gi,'');
	ip1num = 0;
	ip2num = 0;
	ipnum = ip2long(_ip);
	if(ipnum==false) return {"contry":"","info":""}
	//console.log(_ip);
	beginNum = 0;
	endNum = ipallnum;
	b0 = 0x00;
	while(ip1num>ipnum||ip2num<ipnum){
		middle = parseInt((endNum+beginNum)/2);
		buf = ip_buf.slice(ipbegin+middle*7,ipbegin+middle*7+4);
		ip1num = buf.readUInt32LE(0);
		if(ip1num <0) ip1num = Math.pow(2,32);
		if(ip1num>ipnum) {
			endNum = middle;
			continue;
		}
		data_seek_next = ip_buf.slice(ipbegin+middle*7+4,ipbegin+middle*7+7);
		
		bf = buf_add_0(data_seek_next);
		ipData2 = ip_buf.slice(bf.readUInt32LE(0),bf.readUInt32LE(0)+4);
		ip2num = ipData2.readUInt32LE(0);
		if(ip2num<0) ip2num  = Math.pow(2,32);
		//没找到提示未知
		if(ip2num<ipnum){
			if(middle==beginNum){
				return 'unknown';
			}
			beginNum = middle;
		}
		//return;
		//console.log('aa');
	}

	ipFlag = (ip_buf.slice(bf.readUInt32LE(0)+4,bf.readUInt32LE(0)+5).readUInt8(0));
	if(ipFlag == 1){
		return redirect1(ip_buf.slice(bf.readUInt32LE(0)+5,bf.readUInt32LE(0)+8));

	}else if(ipFlag == 2){

		return redirect2(ip_buf.slice(bf.readUInt32LE(0)+5,bf.readUInt32LE(0)+8),bf.readUInt32LE(0)+8);
	}else{
		contry = getInfo(bf.readUInt32LE(0)+4);
		

		f = ip_buf.slice(bf.readUInt32LE(0)+4+contry.length,bf.readUInt32LE(0)+contry.length+5).readUInt8(0);
		if(f==2||f==1){
			_seek = buf_add_0(ip_buf.slice(bf.readUInt32LE(0)+4+contry.length+1,bf.readUInt32LE(0)+4+contry.length+4)).readUInt32LE(0);
			blok   = getInfo(_seek);
		}else{
			blok   = getInfo(bf.readUInt32LE(0)+4+contry.length);
		}

		str_blok = iconv.decode(blok, 'GBK');
		str_contry = iconv.decode(contry, 'GBK');
		return {"contry":str_contry,"info":str_blok}
	}

}


function buf_add_0(buff){
	bf = new Buffer(4);
	bf[0] = buff[0];
	bf[1] = buff[1];
	bf[2] = buff[2];
	bf[3] = b0;
	return bf;
}


function redirect1(buff){
	addbuf = buf_add_0(buff);
	ipseek = addbuf.readUInt32LE(0);
	if(ip_buf.slice(ipseek,1+ipseek).readUInt8(0)==2){
		//重定向2
		return redirect2(ip_buf.slice(ipseek+1,ipseek+4),ipseek+4);	
	}else{

		contry = getInfo(ipseek);
		f = ip_buf.slice(ipseek+contry.length,ipseek+contry.length+1).readUInt8(0);
		if(f==2||f==1){
			_seek = buf_add_0(ip_buf.slice(ipseek+contry.length+1,ipseek+contry.length+4)).readUInt32LE(0);
			blok   = getInfo(_seek);
		}else{
			
			blok   = getInfo(ipseek+contry.length);
		}

		str_blok = iconv.decode(blok, 'GBK');
		str_contry = iconv.decode(contry, 'GBK');
		return {"contry":str_contry,"info":str_blok}
	}
}

function redirect2(buff,src){
	addbuf = buf_add_0(buff);
	ipseek = addbuf.readUInt32LE(0);
	contry = getInfo(ipseek);
	
	if(ip_buf.slice(src,1+src).readUInt8(0)==1||ip_buf.slice(src,1+src).readUInt8(0)==2){
		blok_buf = buf_add_0(ip_buf.slice(src+1,4+src));
		blok = getInfo(blok_buf.readUInt32LE(0));
	}else{

		blok   = getInfo(src);
	}
	str_blok = iconv.decode(blok, 'GBK');
	str_contry = iconv.decode(contry, 'GBK');
	return {"contry":str_contry,"info":str_blok}
	//console.log(str);
}

function getInfo(offset){

	for(i=offset;i<ip_buf.length;i++){
		if(ip_buf[i]==0x00){
			return ip_buf.slice(offset,i+1);
		}
	}
}
 

function ip2long(a){
	var b=0,a=a.match(/^([1-9]\d*|0[0-7]*|0x[\da-f]+)(?:\.([1-9]\d*|0[0-7]*|0x[\da-f]+))?(?:\.([1-9]\d*|0[0-7]*|0x[\da-f]+))?(?:\.([1-9]\d*|0[0-7]*|0x[\da-f]+))?$/i);
	if(!a)return!1;
	a[0]=0;
	for(b=1;b<5;b+=1) 
		a[0]+=!!(a[b]||"").length,a[b]=parseInt(a[b])||0;a.push(256,256,256,256);
	a[4+a[0]]*=Math.pow(256,4-a[0]);
	if(a[1]>=a[5]||a[2]>=a[6]||a[3]>=a[7]||a[4]>=a[8])return!1;
	return a[1]*(a[0]===1||16777216)+a[2]*(a[0]<=2||65536)+a[3]*(a[0]<=3||256)+a[4]*1
};


//var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;

var start_http = function(){
	
	
// Worker processes have a http server.
  http.Server(function(req, res) {
  	start = (new Date()).valueOf();
  	ip = require('url').parse(req.url).pathname.replace("/","");
    res.writeHead(200);
    result = search(ip);
    //console.log( ((new Date()).valueOf()-start)/1000);
    result.contry = result.contry.replace('\u0000','');
    result.info = result.info.replace('\u0000','');
    result = china_city_mapping.mapping(result);
    console.log(req.connection.remoteAddress)
    
    res.end(JSON.stringify(result));

  }).listen(bind_port);
	

}

var start_sock = function(){
	var net = require('net');
	var sock = net.createServer(function(c) { //'connection' listener
	  console.log('server connected');
	  c.on('end', function() {
	    console.log('server disconnected');
	  });
	  c.write('hello\r\n');
	  c.on('data',function(data){
	  	//console.log(data.toString().replace(/\r\n/gi,''));
	  	cmd = data.toString().replace(/\r\n/gi,'');
      if(cmd=='exit'){
        c.end('bye bye');
      }else{
        rs = search(cmd);
	  	  rs.contry = rs.contry.replace('\u0000','');
	      rs.info = rs.info.replace('\u0000','');
	      rs = china_city_mapping.mapping(rs);
	  	  c.write(JSON.stringify(rs)+"\n");
      }
    })
	  //c.write(rs);
	  //c.pipe(c);
	});
	sock.listen(8124, function() { //'listening' listener
	  console.log('socket server 8124 bound');
	});
}

exports.search = function(ip){
	return china_city_mapping.mapping(search(ip));
};

if(typeof require.parent == 'undefined'){
	start_http();
	start_sock();
}
//console.log(search('42.62.184.0'));
